<!DOCTYPE html>
<html lang="en">
	<head>
		<title>Level Editor - CAP 4720 - Daniel Sledd</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<style>
			body {
				font-family: Monospace;
				background-color: #f0f0f0;
				margin: 0px;
				overflow: hidden;
			}

			#oldie { background-color: #ddd !important }
            
            #dropdown{
                width:200px;
                background:#222;
                margin:20px;
            }

            #dropdown li{
                font-family:sans-serif;
              padding:3px 10px 3px 30px;
               color:white;
                cursor:pointer;
            }
            #dropdown li:hover{
                background-color:blue !important;
            }

            #dropdown li.checked{
                background:url(http://cdn1.iconfinder.com/data/icons/fatcow/16x16_0020/accept.png) 0 5px no-repeat;
            }
            
            #gui { position: absolute; top: 110px; left: 86.5% }

            
		</style>
	</head>
	<body>
        
         
         

        
		<script src="libs/three.min.js"></script>

		<script src="js/Detector.js"></script>
        <script src="libs/TrackballControls.js"></script>
        <script src="js/controls/OrbitControls.js"></script>
        <script src='js/libs/dat.gui.min.js'></script>
        <script src='gui.js'></script>
        
       
        <script type="x-shader/x-vertex" id="vertexshader">

            // switch on high precision floats
            #ifdef GL_ES
            precision highp float;
            #endif
            
            attribute float displacement;
            varying vec3 vNormal;

            void main() {

              vNormal = normal;

              // push the displacement into the
              // three slots of a 3D vector so
              // it can be used in operations
              // with other 3D vectors like
              // positions and normals
              vec3 newPosition = position +
                normal * vec3(displacement);

              gl_Position = projectionMatrix *
                            modelViewMatrix *
                            vec4(newPosition, 1.0);
            }

        </script>

        <script type="x-shader/x-fragment" id="fragmentshader">

            #ifdef GL_ES
            precision highp float;
            #endif

            // same name and type as VS
            varying vec3 vNormal;

            void main() {

              // calc the dot product and clamp
              // 0 -> 1 rather than -1 -> 1
              vec3 light = vec3(0.5, 0.2, 1.0);

              // ensure it's normalized
              light = normalize(light);

              // calculate the dot product of
              // the light to the vertex normal
              float dProd = max(0.0,
                                dot(vNormal, light));

              // feed into our frag colour
              gl_FragColor = vec4(dProd, // R
                                  dProd, // G
                                  dProd, // B
                                  1.0);  // A

            }

        </script>

    
    

		<script>

			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
            
            var clock = new THREE.Clock();
			var container;
            var controls;
            var isMouseDown = false, isMouseMove = false;
			var camera, scene, renderer;
			var plane, cube;
			var mouse, raycaster, isShiftDown = false;

			var rollOverMesh, rollOverMaterial;
			var cubeGeo, cubeMaterial;
            var objArray;
            var currBlockType = 0;
            var spawnBlock;
            var line;
            var initSize = 1000;
            var currentPlaneMaterial = 0;
            
            var t = THREE;
            var materials = [
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('textures/white-bricks.jpg')}),
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('images/ground.jpg')}),
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('images/wood.jpg')}),
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('images/stone.png')}), 
                new t.MeshLambertMaterial({color: 0xFBEBCD})
                                 ];
            
            var planeMaterials = [
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('images/ground.jpg')} ),
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('textures/snow.jpg')} ) ,
                new t.MeshLambertMaterial({map: t.ImageUtils.loadTexture('textures/concrete.jpg')} ) 
            ];

			var objects = [];
            
            var block = {
                BRICK : 0,
                GROUND : 1,
                WOOD : 2,
                STONE : 3,
                SPAWN : 4
                
            };
            
            var axis;
            
             
			init();
			render();
            
            
            
            
           
            
            function createArray(length)
            {
                var arr = new Array(length || 0),
                    i = length;

                if (arguments.length > 1) {
                    var args = Array.prototype.slice.call(arguments, 1);
                    while(i--) arr[length-1 - i] = createArray.apply(this, args);
                }

                return arr;
            }
            
            function openWindow()
            {
                saveJSON(false);
                window.open('level.html');
            }
            
            function createButton(name, text, width, height, top, left)
            {
                var button = document.createElement("BUTTON");
                var buttonText = document.createTextNode(text);
                button.appendChild(buttonText);

                button.style.position = 'absolute';
                button.tagName = name;

                button.style.width = width;
                button.style.height = height;
                button.style.top = window.innerHeight/2 + top + 'px';
                button.style.left = window.innerWidth/2 + left + 'px';
                document.body.appendChild(button);

                return button;
            }
            
            
            
			function init() {
                mouseTemp = new THREE.Vector2(0, 0);
                container = document.createElement( 'div' );
				document.body.appendChild( container );
                
               // objArray = createArray(30, 30, 30);
                objArray = [];
				

				var info = document.createElement( 'div' );
				info.style.position = 'absolute';
				info.style.top = '10px';
				info.style.width = '100%';
                //info.style.height = '10%';
				info.style.textAlign = 'center';
                info.style.color = 'green';
                info.style.fontSize = '20px';
                info.style.backgroundColor = 'black';
				info.innerHTML = 'Level Editor - Daniel Sledd <br><strong>click</strong>: add block, <strong>shift + click</strong>: remove block, Access GUI controls to change blocktype, in-game physics, and map size';
				container.appendChild( info );
                
                /*
                var link = document.createElement( 'div');
                link.innerHTML = '<a href="javascript:openWindow();">CLICK ME</a>';
                container.appendChild(link);
                */
                
                
				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 20000 );
				camera.position.set( 0, 800, 1300 );
				camera.lookAt( new THREE.Vector3() );

				scene = new THREE.Scene();

				// roll-over helpers

				rollOverGeo = new THREE.BoxGeometry( 50, 50, 50 );
				rollOverMaterial = new THREE.MeshLambertMaterial( { color: 0xff0000, opacity: 0.5, transparent: true } );
				rollOverMesh = new THREE.Mesh( rollOverGeo, rollOverMaterial );
				scene.add( rollOverMesh );
                
                axis = new THREE.AxisHelper(500);
                axis.position.y += 25;
                axis.position.x -= 1000;
                axis.position.z -= 1000;
                
                //axis.position.x += 2;
                scene.add(axis);
                

				// cubes

				cubeGeo = new THREE.BoxGeometry( 50, 50, 50 );
				cubeMaterial = materials[block.SPAWN];
                
                spawnBlock = new t.Mesh(cubeGeo, cubeMaterial);

                spawnBlock.type = block.SPAWN;
                
                scene.add(spawnBlock);
                objects.push(spawnBlock);
                
				// grid

				var size = 1000, step = 50;
                initSize = size;

				var geometry = new THREE.Geometry();

				for ( var i = - size; i <= size; i += step ) {

					geometry.vertices.push( new THREE.Vector3( - size, 0, i ) );
					geometry.vertices.push( new THREE.Vector3(   size, 0, i ) );

					geometry.vertices.push( new THREE.Vector3( i, 0, - size ) );
					geometry.vertices.push( new THREE.Vector3( i, 0,   size ) );

				}

				var material = new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2, transparent: false } );

				line = new THREE.LineSegments( geometry, material );
				scene.add( line );

				//

				raycaster = new THREE.Raycaster();
				mouse = new THREE.Vector2();

				var geometry = new THREE.PlaneBufferGeometry( 2000, 2000 );
				geometry.rotateX( - Math.PI / 2 );

				plane = new THREE.Mesh( geometry, materials[1]  ) ;
				scene.add( plane );

				objects.push( plane );

				// Lights

				var ambientLight = new THREE.AmbientLight( 0x606060 );
				scene.add( ambientLight );

				var directionalLight = new THREE.DirectionalLight( 0xffffff );
				directionalLight.position.set( 1, 1.75, 0.5 ).normalize();
				scene.add( directionalLight );

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setClearColor( 0xf0f0f0 );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				container.appendChild( renderer.domElement );
                
                // controls
                controls = new THREE.OrbitControls(camera);
                controls.target.set(0,0,0);
                
                // gui
                
                setUpGui();
                
                
                
                //stats = new Stats();
				//stats.domElement.style.position = 'absolute';
				//stats.domElement.style.top = '0px';
				//container.appendChild( stats.domElement );


				document.addEventListener( 'mousemove', onDocumentMouseMove, false );
				document.addEventListener( 'mousedown', onDocumentMouseDown, false );
				document.addEventListener( 'keydown', onDocumentKeyDown, false );
				document.addEventListener( 'keyup', onDocumentKeyUp, false );
                document.addEventListener( 'mouseup', onDocumentMouseUp, false );
                document.addEventListener( 'mousewheel', onDocumentWheel, false);
                document.addEventListener( 'drop', onDrop, false);
                document.addEventListener( 'dragover', onDragOver, false);
                
                // Buttons
                
                var exportButton = createButton("export", "Export Map", 50, 50, -window.innerHeight/2 + 25, window.innerWidth/2 - 125);
                exportButton.addEventListener('click', onExportClick);
                
                var clearButton = createButton("clear", "Clear Map", 50, 50, -window.innerHeight/2 + 25, window.innerWidth/2 - 250);
                clearButton.addEventListener('click', clearScreen);
                
                var playButton = createButton("play", "Play Map", 50, 50, -window.innerHeight/2 + 70, -50);
                playButton.addEventListener('click', openWindow);
                
                
                
                loadSkyMap();
				//
                
                //update();

				window.addEventListener( 'resize', onWindowResize, false );

			}
            
            /*
            function update()
            {
                for (var property in color)
                {
                    if (color.property == 
                }
                requestAnimationFrame(update);
            }
            */
            var skyboxMesh;
            function loadSkyMap()
            {
                
                if (skyboxMesh != null)
                    scene.remove(skyboxMesh);
                
                var skymaptype;
                if (skymap.Mountains)
                    skymaptype = 'mountains';
                else if (skymap.bluefreeze)
                    skymaptype = 'bluefreeze';
                else if (skymap.darkland)
                    skymaptype = 'darkland';
                else if (skymap.city)
                    skymaptype = 'city';
                else if (skymap.comawhite)
                    skymaptype = 'comawhite';
                else
                    console.log("no value found");
                
                // skybox
                var urlPrefix = "textures/" + skymaptype + "/";
                var urls = [ urlPrefix + "right.jpg", urlPrefix + "left.jpg",
                    urlPrefix + "top.jpg", urlPrefix + "top.jpg",
                    urlPrefix + "front.jpg", urlPrefix + "back.jpg"];
                var textureCube = THREE.ImageUtils.loadTextureCube( urls );

                var shader = THREE.ShaderLib["cube"];
                var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
                uniforms['tCube'].value = textureCube;   // textureCube has been init before
                
                var material = new THREE.ShaderMaterial({
                    fragmentShader    : shader.fragmentShader,
                    vertexShader  : shader.vertexShader,
                    uniforms  : uniforms,
                    depthWrite: false,
                    side: THREE.DoubleSide
                });
                
                // build the skybox Mesh 
                skyboxMesh    = new THREE.Mesh( new THREE.BoxGeometry( 10000, 10000, 10000, 1, 1, 1), material );
                // add it to the scene
                scene.add( skyboxMesh );
                updateSquareGrid(menu.Map_Size/2);
                
            }
            
            
            function onExportClick()
            {
                //var jsonArray = JSON.parse(JSON.stringify(objArray));
                
                saveJSON(true);
                
                //console.log(jsonArray.toString);
                
            }
            
            function onDragOver(event)
            {
                event.preventDefault();
            }
            
            function onDocumentWheel( event )
            {
                event.preventDefault();
                render();
                //controls.update();
            }

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function onDocumentMouseMove( event ) {

				//event.preventDefault();

                
				
                mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );
                
                mouseTemp.x += mouse.x;
                mouseTemp.y += mouse.y;
                
                isMouseMove = true;
                
				raycaster.setFromCamera( mouse, camera );

				var intersects = raycaster.intersectObjects( objects );
                
                //console.log(intersects.length);

				if ( intersects.length > 0 ) {

					var intersect = intersects[ 0 ];
                    //rollOverMesh.visibility = false;

					rollOverMesh.position.copy( intersect.point ).add( intersect.face.normal );
					rollOverMesh.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );
                    
                
                    

				}

				render();

			}

            var mouseTemp;
			function onDocumentMouseDown( event ) {

				event.preventDefault();
                
                isMouseDown = true;
                isMouseMove = false;
                
                mouseTemp = new THREE.Vector2(0, 0);

				

			}
            
            function onDocumentMouseUp( event ) {
                
                event.preventDefault();
                isMouseDown = false;
                
                mouse.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1 );

				raycaster.setFromCamera( mouse, camera );

				var intersects = raycaster.intersectObjects( objects );
                
                //console.log(mouseTemp.length())

				if ( intersects.length > 0 ) {

					var intersect = intersects[ 0 ];

					// delete cube

					if ( isShiftDown ) {

						if ( intersect.object != plane && intersect.object != spawnBlock ) {

							scene.remove( intersect.object );

							objects.splice( objects.indexOf( intersect.object ), 1 );

						}

					// create cube
                        
					} else {
                        if (mouseTemp.length() <= 3)
                        {
                            if (currBlockType == block.SPAWN)
                            {
                                scene.remove(spawnBlock)
                                objects.splice(objects.indexOf(spawnBlock), 1);
                                
                                spawnBlock = new THREE.Mesh( cubeGeo, materials[currBlockType] );
                                spawnBlock.type = 4;
                                spawnBlock.static = menu.static;
                                
                                spawnBlock.position.copy( intersect.point ).add( intersect.face.normal );
                                //console.log(voxel.position);

                                spawnBlock.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );
                            
                                //console.log(voxel.position);
                                scene.add( spawnBlock );
                                objects.push(spawnBlock);
                                rollOverMesh.visible = false;
                            }
                            else{
                                
                                var voxel = new THREE.Mesh( cubeGeo, materials[currBlockType] );
                                voxel.type = currBlockType;
                                voxel.static = menu.static;
                                //console.log(intersect.face.normal);
                                //console.log(intersect.point);
                                //console.log(intersect.point.add(intersect.face.normal));
                                voxel.position.copy( intersect.point ).add( intersect.face.normal );
                                //console.log(voxel.position);

                                voxel.position.divideScalar( 50 ).floor().multiplyScalar( 50 ).addScalar( 25 );

                                //console.log(voxel.position);
                                scene.add( voxel );

                                objects.push( voxel );
                                objArray.push(voxel);
                                rollOverMesh.visible = false;
                            }
                        }

					}

					//render();

				}
            }

			function onDocumentKeyDown( event ) {

				switch( event.keyCode ) {

					case 16: isShiftDown = true; color.red = false; break;

				}
                
                render();

			}

			function onDocumentKeyUp( event ) {

				switch ( event.keyCode ) {

					case 16: isShiftDown = false; break;

				}
                render();

			}
            
            function onDrop(event) {
				event.preventDefault();
				for(var i = 0; i < event.dataTransfer.files.length; i++){
					var file = event.dataTransfer.files[i];
					var reader = new FileReader();
					reader.onload = function (event){
						var dataUri	= event.target.result;
						var base64 = dataUri.match(/[^,]*,(.*)/)[1];
						var json = window.atob(base64);
						loadJSON( json )
					};
					reader.readAsDataURL(file);
				}
			}
            var voxels;
            
            function saveJSON(openWindow) {
				var children = scene.children;
				 voxels	= [];
				for( var i = 0; i < children.length; i++ ) {
					var child = children[i];
					if( child instanceof THREE.Mesh === false ) continue;
					if( child.geometry instanceof THREE.CubeGeometry === false ) continue;
					if( child === rollOverMesh ) continue;
                    if( child === skyboxMesh ) continue;
					voxels.push({
						x	: (child.position.x - 25) / 50,
						y	: (child.position.y - 25) / 50,
						z	: (child.position.z - 25) / 50,
						t	: child.type,
                        static : child.static
					});
				}
				
                
                
				// if we hit the export button, open a window with the json
                if (openWindow)
                {
                    var dataUri	= "data:application/json;charset=utf-8,"+JSON.stringify(voxels);
                    window.open( dataUri, 'mywindow' );
                }
			}
            
            function loadJSON(mapJSON) {
				// delete all cubes
				var children	= scene.children.slice(0);
				for( var i = 0; i < children.length; i++ ) {
					if( children[i] instanceof THREE.Mesh === false ) continue;
					if( children[i].geometry instanceof THREE.CubeGeometry === false ) continue;
					if( children[i] === rollOverMesh ) continue;
                    if (children[i] == skyboxMesh) continue;
                    
                    objects.splice(objects.indexOf(children[i]), 1);
					scene.remove( children[i] );
                    
				}				
				// push new cubes
                voxels = [];
                voxels	= JSON.parse(mapJSON);
				for( var i = 0; i < voxels.length; i++ ){
					var voxel = voxels[i];
					var mesh = new THREE.Mesh( cubeGeo, materials[voxel.t] );
					mesh.position.x = voxel.x * 50 + 25;
					mesh.position.y = voxel.y * 50 + 25;
					mesh.position.z = voxel.z * 50 + 25;
                    //conole.log('hello');
                    //console.log("this is the static: " + voxel.static);
                    mesh.type = voxel.t;
                    mesh.static = voxel.static;
					mesh.matrixAutoUpdate = true;
                    
                    if (voxel.t == block.SPAWN)
                    {
                        spawnBlock = mesh;
                        //scene.remove(spawnBlock);
                    }
                    
					mesh.updateMatrix();
					scene.add( mesh );
                    objects.push(mesh);
					
				}
			}
            
            function clearScreen()
            {
                // delete all cubes
				var children	= scene.children.slice(0);
				for( var i = 0; i < children.length; i++ ) {
					if( children[i] instanceof THREE.Mesh === false ) continue;
					if( children[i].geometry instanceof THREE.CubeGeometry === false ) continue;
					if( children[i] === rollOverMesh ) continue;
                    if( children[i] === spawnBlock) continue;
                    if (children[i] == plane) continue;
                    if (children[i] == skyboxMesh) continue;
                    
                    objects.splice(objects.indexOf(children[i]), 1);
					scene.remove( children[i] );
                    
				}		
            }

			function render() {
                
                var delta = clock.getDelta();
                controls.update();
                
                
                //console.log(isShiftDown);
                
                if (isShiftDown)
                    rollOverMesh.visible = false;
                else
                    rollOverMesh.visible = true;

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>
